﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RainEngine.Rendering;
using RainEngine.SceneManagement;
using System.ComponentModel;
using RainEngine.Effects;
using System;
using Microsoft.Xna.Framework.Content;

namespace RainEngine.SceneNodes
{
    /// <summary>
    /// 场景中的所有3D可视对象必须从这个类继承。
    /// Draw()必须被继承的类重写
    /// </summary>
    public abstract class Renderable3DSceneNode : SceneNode 
    {
        #region 构造函数和成员变量

        /// <summary>
        /// 加载内容所需的管理器
        /// </summary>
        protected ContentManager content;

        /// <summary>
        /// 节点是否可见
        /// </summary>
        protected bool visible = true;  

        /// <summary>
        /// 绕x, y和z轴的旋转角度
        /// </summary>
        protected Vector3 angleRotation;

        /// <summary>
        /// 保存每帧的状态位标志。
        /// </summary>
        internal StatusBits frameBits;

        /// <summary>
        /// 是否可以被水面反射
        /// </summary>
        protected bool isReflected;        

        /// <summary>
        /// 是否可以被水面折射
        /// </summary>
        protected bool isRefracted;
        

        /// <summary>
        /// 创建一个新RenderableScene3DNode对象
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="setScene">所属场景</param>      
        public Renderable3DSceneNode(GraphicsDevice graphicsDevice, ContentManager setContent,Scene setScene)
            : base(graphicsDevice,setScene)          
        {
            this.content = setContent;
            Pose = new WorldPose();
            Pose.Node = this;
            AngleRotation = Vector3.Zero;   
            Enabled = true;
            Visible = true;
            FarPlaneCullingFactor = 1;
        }      
        
        #endregion       

        #region 属性        

        /// <summary>
        /// 获取或设置节点的旋转角度
        /// </summary> 
        [Browsable(false)]
        public Vector3 AngleRotation
        {
            get
            {
                return angleRotation;
            }
            set
            {
                angleRotation = new Vector3(value.X % 360, value.Y % 360, value.Z % 360);
            }
        }

        /// <summary>
        /// 获取或设置节点的Pose，Pose包含了节点的平移、缩放和旋转信息
        /// </summary> 
        public WorldPose Pose
        {
            get;
            set;
        }

        /// <summary>
        /// 获取或设置节点的Enabled状态。Enabled的节点仍是可见的，绘制但不更新。
        /// </summary>        
        public bool Enabled
        {
            get
            {
                return ((byte)frameBits & (byte)StatusBits.Enabled) != 0;
            }
            set
            {
                if (value)
                    frameBits = (StatusBits)((byte)frameBits | (byte)StatusBits.Enabled);
                else
                    frameBits = (StatusBits)((byte)frameBits & (byte.MaxValue - (byte)StatusBits.Enabled));
            }
        }
        /// <summary>
        /// 如果设为false，则节点总是被更新，如果设为true，则只有当节点的包围球位于相机视锥体之内才会被更新。
        /// </summary>        
        public virtual bool DisableUpdateCulling
        {
            get
            {
                return ((byte)frameBits & (byte)StatusBits.DisableUpdateCulling) != 0;
            }
            set
            {
                if (value)
                    frameBits = (StatusBits)((byte)frameBits | (byte)StatusBits.DisableUpdateCulling);
                else
                    frameBits = (StatusBits)((byte)frameBits & (byte.MaxValue - (byte)StatusBits.DisableUpdateCulling));
            }
        }        

        /// <summary>
        /// 获取或设置标志，这个标志告知引擎是否关闭对这个节点进行的剔除计算。
        /// 默认为false，即需要进行剔除计算。有时希望关闭剔除，让有些几何体总是被绘制（例如天空球）        
        /// </summary>  
        [Category("剪裁")]
        [Description("获取或设置标志，这个标志告知引擎是否关闭对这个节点进行的剔除计算。默认为false，即需要进行剔除计算。有时希望关闭剔除，让有些几何体总是被绘制（例如天空球）")]
        public virtual bool DisableCulling
        {
            get
            {
                return ((byte)frameBits & (byte)StatusBits.DisableCulling) != 0;
            }
            set
            {
                if (value)
                    frameBits = (StatusBits)((byte)frameBits | (byte)StatusBits.DisableCulling);
                else
                    frameBits = (StatusBits)((byte)frameBits & (byte.MaxValue - (byte)StatusBits.DisableCulling));
            }
        }

        /// <summary>
        /// 获取会设置节点是否可见，如果设为false则节点不会被绘制。
        /// </summary>
        public bool Visible
        {
            get
            {
                return ((byte)frameBits & (byte)StatusBits.Visible) != 0;
            }
            set
            {
                if (value)
                    frameBits = (StatusBits)((byte)frameBits | (byte)StatusBits.Visible);
                else
                    frameBits = (StatusBits)((byte)frameBits & (byte.MaxValue - (byte)StatusBits.Visible));
            }
        }

        /// <summary>
        /// 获取或设置与相机逻辑远裁平面相关的因子。
        /// 剔除距离为Camera.FarPLane * FarPlaneCullingFactor。
        /// 这个值默认为1。如果设为0或负数则该节点不会进行剔除，但这时设置<see cref="DisableCulling"/>属性更好
        /// </summary> 
        [Category("剪裁")]
        [Description("获取或设置与相机逻辑远裁平面相关的因子。剔除距离为Camera.FarPLane * FarPlaneCullingFactor。这个值默认为1。如果设为0或负数则该节点不会进行剔除，但这时设置DisableCulling属性效率更高。")]
        public float FarPlaneCullingFactor { get; set; }

        /// <summary>
        /// 获取或设置是否可以被水面反射
        /// </summary>
        [Category("水面效果")]
        [Description("如果这个值设置为true，该节点会在水面上留下反射的图像。")]
        public bool IsReflected
        {
            get { return isReflected; }
            set { isReflected = value; }
        }

        /// <summary>
        /// 获取或设置是否可以被水面折射
        /// </summary>
        [Category("水面效果")]
        [Description("如果这个值设置为true，该节点会在水面下留下折射的图像。")]
        public bool IsRefracted
        {
            get { return isRefracted; }
            set { isRefracted = value; }
        }        

        /// <summary>
        /// Gets, sets the shadowing behavior of the node. If true the node will cast shadows else it will not be included in the shadow calculation.
        /// </summary>
        //public bool IsShadowCaster { get; set; }

        /// <summary>
        /// 当Visible属性改变时引发的事件。
        /// </summary>
        public event EventHandler VisibleChanged;

        /// <summary>
        ///  VisibleChanged事件的处理程序。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnVisibleChanged(EventArgs e)
        {
            if (VisibleChanged != null)
                VisibleChanged(this.visible, e);
        }

        #endregion

        internal virtual void LoadContent()
        {
            
        }
           
        public override void Initialize()
        {
            if (graphicsDevice.IsDisposed)
                return;
            LoadContent();
            isInitialized = true;
        }

        public abstract int Draw(GameTime gameTime, Matrix ViewMatrix, Matrix ProjectionMatrix, Vector3 CameraPosition);

        public abstract void SetClipPlane(Vector4? Plane);
        
    }
}
